package com.ych.redis.util;

import com.ych.redis.exception.ShareLockException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @BelongsProject: ape-frame
 * @BelongsPackage: com.ych.redis.util
 * @Author: ych
 * @CreateTime: 2024-11-26  14:41
 * @Description: TODO
 * @Version: 1.0
 */

@Component
@Slf4j
public class RedisShareLockUtil {

    private static final long TIME_OUT = 5000L;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 加锁方法
     *
     * @param key       锁
     * @param requestId 请求唯一标识
     * @param time      加锁时长
     * @return
     */
    public Boolean lock(String key, String requestId, Long time) {
        boolean result = false;
        if (StringUtils.isBlank(key) || StringUtils.isBlank(requestId) || time <= 0) {
            log.error("分布式锁-参数异常");
            throw new ShareLockException("分布式锁-参数异常");
        }
        long currentTime = System.currentTimeMillis();
        long outTime = currentTime + TIME_OUT;
        //自旋操作
        while (currentTime < outTime) {
            //采用Redis的命令setnx实现加锁
            result = redisUtil.setNx(key, requestId, time, TimeUnit.MILLISECONDS);
            if (result) {
                return result;
            }
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            currentTime = System.currentTimeMillis();
        }
        return result;
    }


    /**
     * 释放锁
     *
     * @param key       锁
     * @param requestId 请求唯一标识
     * @return
     */
    public Boolean unLock(String key, String requestId) {
        if (StringUtils.isBlank(key) || StringUtils.isBlank(requestId)) {
            log.error("分布式锁-解锁参数异常");
            throw new ShareLockException("分布式锁-解锁参数异常");
        }
        if (!requestId.equals(redisUtil.get(key))) {
            return false;
        }
        return redisUtil.del(key);
    }

    /**
     * 尝试加锁无自旋
     *
     * @param key       锁
     * @param requestId 请求唯一标识
     * @param time      加锁时长
     * @return
     */
    public Boolean tryLock(String key, String requestId, Long time) {
        if (StringUtils.isBlank(key) || StringUtils.isBlank(requestId) || time <= 0) {
            log.error("分布式锁-尝试加锁参数异常");
            throw new ShareLockException("分布式锁-尝试加锁参数异常");
        }
        return redisUtil.setNx(key, requestId, time, TimeUnit.MILLISECONDS);
    }
}
